﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TileCreator : MonoBehaviour
{
    private AStarWrapper Astar = null;
    public bool isFileter = false;

    //读图的宽高
    public int Width;
    public int Height;
    //测试用材质
    public bool debugNow = false;
    public Material Go;
    public Material Stop;
    public Material[] GridTypeMaterial;
    //格子大小
    public float Size = 1.0f;
    //结构图
    public Texture2D Map;
    //换成bool的结构图
    public bool[,] GoMap;
    //格子的类别
    //拐角，半墙，墙根，空地
    public GameObject[] Prefabs;

    public Transform StartPointer;
    public Transform EndPointer;

    // Use this for initialization
    void Awake()
    {
        ReadMap();
        CreatePoint();
        CreatGrid();
    }

    void Start() {
        this.Astar = new AStarWrapper();
        Astar.InitWithMapData(this.GoMap, this.Width, this.Height, this.Size);
    }

    void Update() {
        if (this.StartPointer != null && this.EndPointer != null) {
            Astar.AstarSearch(this.StartPointer.position, this.EndPointer.position);
        }
        
    }

    private void OnDrawGizmos()
    {
        if (this.Astar == null) {
            return;
        }

        List<PathNode> FoundPath = Astar.GetFoundPath();
        List<PathNode> AfterFilteFoundPath = Astar.GetFilterFoundPath();
        if (FoundPath != null)
        {
            Gizmos.color = Color.blue;
            float Size = this.Size;
            // Vector3 StartPoint = new Vector3(FoundPath[0].indexI * Size, 0, FoundPath[0].indexJ * Size);
            Vector3 StartPoint = this.StartPointer.position;
            Vector3 EndPoint = Vector3.zero;
            for (int i = 1; i < FoundPath.Count - 1; i++)
            {
                EndPoint = new Vector3(FoundPath[i].indexI * Size, 0, FoundPath[i].indexJ * Size);
                Gizmos.DrawLine(StartPoint, EndPoint);
                StartPoint = EndPoint;
            }
            Gizmos.DrawLine(StartPoint, this.EndPointer.position);
        }

        if (this.isFileter && AfterFilteFoundPath != null && AfterFilteFoundPath.Count >= 2)
        {
            Gizmos.color = Color.red;

            float Size = this.Size;
            // Vector3 StartPoint = new Vector3(this.AfterFilteFoundPath[0].x * Size, 0, this.AfterFilteFoundPath[0].y * Size);
            Vector3 StartPoint = this.StartPointer.position;
            Vector3 EndPoint = Vector3.zero;
            for (int i = 1; i < AfterFilteFoundPath.Count - 1; i++)
            {
                EndPoint = new Vector3(AfterFilteFoundPath[i].indexI * Size, 0, AfterFilteFoundPath[i].indexJ * Size);
                Gizmos.DrawLine(StartPoint, EndPoint);
                StartPoint = EndPoint;
            }
            Gizmos.DrawLine(StartPoint, this.EndPointer.position);
        }
    }

    public void ReadMap()
    {
        //按颜色来读图
        GoMap = new bool[Width, Height];
        for (int i = 0; i < Width; i++)
        {
            for (int j = 0; j < Height; j++)
            {
                Color P = Map.GetPixel(i, j);
                float value = (P.b + P.g + P.r) / 3;
                GoMap[i, j] = value >= 0.5;
            }
        }
    }

    public void CreatePoint()
    {
        GameObject root = new GameObject("root");
        Transform rootTr = root.transform;
        //根据图创建点
        Renderer Rer;
        for (int i = 0; i < Height; i++)
        {
            for (int j = 0; j < Width; j++)
            {
                //创建最简单的东西
                GameObject GPointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
                GPointer.transform.SetParent(rootTr);
                Rer = GPointer.GetComponent<Renderer>();
                //换材质
                Rer.material = GoMap[i, j] ? Go : Stop;
                //调整位置
                GPointer.transform.position = new Vector3(i * Size, 0, j * Size);
                GPointer.transform.localScale = Vector3.one * 0.25f;
                GPointer.name = i.ToString() + "   " + j.ToString();
            }
        }
    }
    //创建地图
    public void CreatGrid()
    {
        GameObject root = new GameObject("grid root");
        Transform rootTr = root.transform;
        bool[] GridIndex = new bool[4];
        Renderer Rer;
        for (int i = 0; i < Height; i++)
        {
            for (int j = 0; j < Width; j++)
            {
                //确认边界
                GridIndex[0] = GoMap[i, j]; // 自己这个点；
                if (i + 1 != Width)
                    GridIndex[1] = GoMap[i + 1, j];
                else
                    GridIndex[1] = false;
                if (j + 1 != Height)
                    GridIndex[2] = GoMap[i, j + 1];
                else
                    GridIndex[2] = false;
                if (i + 1 != Width && j + 1 != Height)
                    GridIndex[3] = GoMap[i + 1, j + 1];
                else
                    GridIndex[3] = false;
                //数01，看数出来什么类型
                int type = CheckPoint(GridIndex);
                if (type == 0)
                    continue;
                GameObject GPointer;
                if (debugNow)
                {
                    //Debug的话，就用看得明显点的
                    GPointer = GameObject.CreatePrimitive(PrimitiveType.Plane);
                    GPointer.transform.localScale = Vector3.one * 0.3f;
                    GPointer.transform.position = new Vector3(i * Size + Size * 0.5f, 0, j * Size + Size * 0.5f);
                    Rer = GPointer.GetComponent<Renderer>();
                    Rer.material = GridTypeMaterial[type - 1];
                }
                else
                {
                    //不是的话，就用我们实际的Prefab
                    GPointer = GameObject.Instantiate<GameObject>(Prefabs[type - 1]);
                    GPointer.transform.position = new Vector3(i * Size + Size * 0.5f, 0, j * Size + Size * 0.5f);
                }
                GPointer.transform.SetParent(rootTr);
                GPointer.name = $"{i}__{j}";
                //根据类别判断旋转
                if (type ==1)
                {
                    int R = CheckCornerRotation(GridIndex);
                    GPointer.transform.rotation = Quaternion.Euler(0, R*90.0f, 0);
                }
                if (type ==3)
                {
                    int R = CheckSupportWallRotation(GridIndex);
                    GPointer.transform.rotation = Quaternion.Euler(0, R * 90.0f, 0);
                }
                if (type == 2)
                {
                    int R = CheckHalfWallRotation(GridIndex);
                    GPointer.transform.rotation = Quaternion.Euler(0, R * 90.0f, 0);
                }
            }
        }
    }

    //       -----------------
    //       |       |       |
    //       | LU0   |   RU1 |
    //       |---------------|
    //       | LD2   |   RD3 |
    //       |       |       |
    //       -----------------
    //         byte LU0 RU1 LD2 RD3
    private int CheckPoint(bool[] Index)
    {
        //1个能走拐角Corner
        //2个能走半墙HalfWall
        //3个能走墙根SupportWall
        //4个能走空地Blank
        int type = 0;
        for (int i = 0; i < 4; i++)
        {
            if (Index[i])
                type++;
        }
        return type;
    }

    private int CheckCornerRotation(bool[] Index)
    {
        int iR = 0;
        for (int i = 0; i < 4; i++)
        {
            if (Index[i])
                iR = i;
        }
        switch (iR)
        {
            case 0:
                iR = 1;
                break;
            case 1:
                iR = 0;
                break;
            case 2:
                iR = 2;
                break;
            case 3:
                iR = 3;
                break;
        }
        return iR;
    }
    private int CheckHalfWallRotation(bool[] Index)
    {
        int iR = 0;
        if (Index[0] && Index[1])
        {
            iR = 0;
        }
        if (Index[0] && Index[2])
        {
            iR = 1;
        }
        if (Index[2] && Index[3])
        {
            iR = 2;
        }
        if (Index[3] && Index[1])
        {
            iR = 3;
        }
        return iR;
    }
    private int CheckSupportWallRotation(bool[] Index)
    {
        int iR = 0;
        for (int i = 0; i < 4; i++)
        {
            if (!Index[i])
                iR = i;
        }
        switch (iR)
        {
            case 0:
                iR = 1;
                break;
            case 1:
                iR = 0;
                break;
            case 2:
                iR = 2;
                break;
            case 3:
                iR = 3;
                break;
        }
        return iR;
    }
}
